/* SDLWindow.cpp
 *
 * --
 * Copyright (c) 2012, Christophe Huriaux
 * Distributed under the terms of the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 * --
 */

#include <graphics/SDLWindow.h>
#include <debug/logger.h>

SDLWindow::SDLWindow(const char* title, unsigned int width,
		unsigned int height, unsigned int bpp, bool fullscreen)
	: Thread("SDL Window"), windowWidth(width), windowHeight(height),
	  windowBpp(bpp), windowTitle(title), fullscreen(fullscreen), screen(NULL),
	  inputGrabbed(false), lastMotionX(0), lastMotionY(0), mouseMoved(false)
{
}

SDLWindow::SDLWindow(const char* title, unsigned int width,
		unsigned int height, unsigned int bpp)
	: Thread("SDL Window"), windowWidth(width), windowHeight(height),
	  windowBpp(bpp), windowTitle(title), fullscreen(false), screen(NULL),
	  inputGrabbed(false), lastMotionX(0), lastMotionY(0), mouseMoved(false)
{
}

SDLWindow::SDLWindow(const char* title, unsigned int width,
		unsigned int height)
	: Thread("SDL Window"), windowWidth(width), windowHeight(height),
	  windowBpp(32), windowTitle(title), fullscreen(false), screen(NULL),
	  inputGrabbed(false), lastMotionX(0), lastMotionY(0), mouseMoved(false)
{
}

SDLWindow::~SDLWindow()
{
	stop();
}

int
SDLWindow::open()
{
	if (updateVideoMode() < 0)
		return -1;

	return start();
}

int
SDLWindow::setWidth(unsigned int width)
{
	windowWidth = width;
	if (screen != NULL)
		return updateVideoMode();
	else
		return 0;
}

int
SDLWindow::setHeight(unsigned int height)
{
	windowHeight = height;
	if (screen != NULL)
		return updateVideoMode();
	else
		return 0;
}

int
SDLWindow::setBpp(unsigned int bpp)
{
	windowBpp = bpp;
	if (screen != NULL)
		return updateVideoMode();
	else
		return 0;
}


void
SDLWindow::setTitle(std::string& title)
{
	windowTitle = title;
	SDL_WM_SetCaption(windowTitle.c_str(), NULL);
}

int
SDLWindow::setFullscreen(bool fs)
{
	fullscreen = fs;

	if (screen != NULL)
		return updateVideoMode();
	else
		return 0;
}

int
SDLWindow::updateVideoMode()
{
	return updateVideoMode(0);
}

int
SDLWindow::updateVideoMode(int flags)
{
	bool rerun = false;
	if (isAlive())
	{
		stop();
		join();
		rerun = true;
	}

	videoModeAdditionalFlags = flags;

	if (rerun)
		start();
	return 0;
}

int
SDLWindow::init()
{
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		logg(critical) << "Unable to init video: " << SDL_GetError() << logg::endl;
		return -1;
	}
	return 0;
}

int
SDLWindow::setVideoMode()
{
	screen = SDL_SetVideoMode(windowWidth, windowHeight, windowBpp,
			SDL_HWSURFACE | (fullscreen?SDL_FULLSCREEN:0) | videoModeAdditionalFlags);
	if (screen == NULL)
	{
		logg(critical) << "Unable to set video mode: " << SDL_GetError() << logg::endl;
		return -1;
	}

	SDL_WM_SetCaption(windowTitle.c_str(), NULL);
	return 0;
}

void*
SDLWindow::run()
{
	unsigned int tNow, tOld;
	SDL_Event event;

	if (init() < 0)
		return NULL;

	if (setVideoMode() < 0)
		return NULL;

	atLaunch();
	while (!shouldStop())
	{
		if (SDL_PollEvent(&event))
		{
			switch (event.type)
			{
				case SDL_QUIT:
					stop();
					break;

				case SDL_KEYDOWN:
					keys.set(event.key.keysym.sym);
					break;

				case SDL_KEYUP:
					keys.reset(event.key.keysym.sym);
					if (event.key.keysym.sym == SDLK_ESCAPE && inputGrabbed)
					{
						logg(debug) << "Input released." << logg::endl;
						inputGrabbed = false;
						SDL_WM_GrabInput(SDL_GRAB_OFF);
						SDL_ShowCursor(SDL_ENABLE);
					}
					break;

				case SDL_MOUSEBUTTONUP:
					if (event.button.button == SDL_BUTTON_LEFT && !inputGrabbed)
					{
						logg(debug) << "Input grabbed." << logg::endl;
						inputGrabbed = true;
						SDL_WM_GrabInput(SDL_GRAB_ON);
						SDL_ShowCursor(SDL_DISABLE);
					}
					break;

				case SDL_MOUSEMOTION:
					if (inputGrabbed)
					{
						mouseMoved = true;
						lastMotionX = event.motion.xrel;
						lastMotionY = event.motion.yrel;
					}
					else
						mouseMoved = false;
					break;
			}
		}
		else
			usleep(1000);

		tNow = SDL_GetTicks();
		if (tNow - tOld > 25)
		{
			tOld = tNow;
			callbackLoop();
		}
	}
	return NULL;
}

void
SDLWindow::atCleanup()
{
	SDL_Quit();
	screen = NULL;
}
